package cn.org.rookie.jeesdp.mapper.sql;

import cn.org.rookie.jeesdp.mapper.sql.condition.*;
import cn.org.rookie.jeesdp.mapper.utils.ObjectUtils;

import java.lang.reflect.Field;
import java.util.*;

/**
 * SQL查询条件包装器，用于构建动态SQL查询条件
 * 支持各种查询条件组合，如等于、不等于、大于、小于、模糊查询、IN查询、空值判断等
 * 同时支持排序条件的设置
 */
public class Wrapper {

    /**
     * 查询条件列表
     */
    private final List<Condition> conditions = new ArrayList<>();

    /**
     * 参数映射表，用于存储条件中的参数值
     */
    private final Map<String, Object> paramMap = new HashMap<>();

    /**
     * 排序条件列表
     */
    private final List<String> orders = new ArrayList<>();

    /**
     * 条件连接符标志，true表示AND连接，false表示OR连接
     */
    private boolean and = true;

    /**
     * 私有构造函数，防止直接实例化
     */
    private Wrapper() {
    }

    /**
     * 创建一个空的查询条件包装器
     *
     * @return 新的查询条件包装器实例
     */
    public static Wrapper init() {
        return new Wrapper();
    }

    /**
     * 根据实体对象创建查询条件包装器
     * 自动将实体对象中非空非空的字段转换为等值查询条件
     *
     * @param entity 实体对象
     * @return 包含实体对象字段查询条件的包装器实例
     */
    public static Wrapper init(Object entity) {
        return init(entity, init());
    }

    /**
     * 根据实体对象创建查询条件包装器，并添加到指定的包装器中
     *
     * @param entity  实体对象
     * @param wrapper 目标包装器
     * @return 包含实体对象字段查询条件的包装器实例
     */
    @SuppressWarnings("CallToPrintStackTrace")
    public static Wrapper init(Object entity, Wrapper wrapper) {
        List<Field> fields = ObjectUtils.getAllFields(entity.getClass());
        for (Field field : fields) {
            String name = field.getName();
            try {
                Object o = field.get(entity);
                if (o != null && !"".equals(o)) {
                    wrapper.equal("\"" + name + "\"", o);
                }
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
        return wrapper;
    }

    /**
     * 添加带参数的查询条件
     *
     * @param columnName 列名
     * @param param      参数值
     * @param condition  条件类型
     * @param sharp      是否使用#{}语法，false表示使用${}语法
     * @return 当前包装器实例，支持链式调用
     */
    private Wrapper add(String columnName, Object param, Condition condition, boolean sharp) {
        if (!sharp) {
            condition.setPrefix("$");
        }
        paramMap.put(columnName, param);
        condition.setColumnName(columnName);
        condition.setIsAnd(and);
        conditions.add(condition);
        return this;
    }

    /**
     * 添加不带参数的查询条件
     *
     * @param columnName 列名
     * @param condition  条件类型
     * @return 当前包装器实例，支持链式调用
     */
    private Wrapper add(String columnName, Condition condition) {
        condition.setColumnName(columnName);
        condition.setIsAnd(and);
        conditions.add(condition);
        return this;
    }

    /**
     * 添加等于条件
     *
     * @param columnName 列名
     * @param param      参数值
     * @return 当前包装器实例，支持链式调用
     */
    public Wrapper equal(String columnName, Object param) {
        return add(columnName, param, new Equal(), true);
    }

    /**
     * 添加不等于条件
     *
     * @param columnName 列名
     * @param param      参数值
     * @return 当前包装器实例，支持链式调用
     */
    public Wrapper notEqual(String columnName, Object param) {
        return add(columnName, param, new NotEqual(), true);
    }

    /**
     * 添加小于条件
     *
     * @param columnName 列名
     * @param param      参数值
     * @return 当前包装器实例，支持链式调用
     */
    public Wrapper less(String columnName, Object param) {
        return add(columnName, param, new Less(), true);
    }

    /**
     * 添加大于条件
     *
     * @param columnName 列名
     * @param param      参数值
     * @return 当前包装器实例，支持链式调用
     */
    public Wrapper greater(String columnName, Object param) {
        return add(columnName, param, new Greater(), true);
    }

    /**
     * 添加模糊查询条件
     *
     * @param columnName 列名
     * @param param      参数值
     * @return 当前包装器实例，支持链式调用
     */
    public Wrapper like(String columnName, Object param) {
        return add(columnName, param, new Like(), false);
    }

    /**
     * 添加IN查询条件
     *
     * @param columnName 列名
     * @param param      参数值数组
     * @return 当前包装器实例，支持链式调用
     */
    public Wrapper in(String columnName, Object[] param) {
        return add(columnName, param, new In(), true);
    }

    /**
     * 添加IS NULL条件
     *
     * @param columnName 列名
     * @return 当前包装器实例，支持链式调用
     */
    public Wrapper isNull(String columnName) {
        return add(columnName, new IsNull());
    }

    /**
     * 添加IS NOT NULL条件
     *
     * @param columnName 列名
     * @return 当前包装器实例，支持链式调用
     */
    public Wrapper isNotNull(String columnName) {
        return add(columnName, new IsNotNull());
    }

    public Wrapper order(String order) {
        this.orders.add(order);
        return this;
    }

    public Wrapper and() {
        and = true;
        return this;
    }

    public Wrapper or() {
        and = false;
        return this;
    }

    public Map<String, Object> getParams() {
        return paramMap;
    }

    public List<Condition> getConditions() {
        return conditions;
    }

    public List<String> getOrder() {
        return orders;
    }

    public Wrapper orderBy(String... orders) {
        this.orders.addAll(Arrays.asList(orders));
        return this;
    }
}

